#pragma once
#include <iostream>
#include <string>
#include <cassert>
#include <unordered_map>
#include <functional>
#include <ctime>
#include "Epoller.hpp"
#include "Sock.hpp"
#include "Log.hpp"
#include "Err.hpp"
#include "Util.hpp"
#include "Protocol.hpp"

using namespace Protocol_ns;

const static uint16_t gport = 8888;
const static int bsize = 1024;
const static int linkTimeout = 30;

class Connection;
class EpollServer;

using func_t = std::function<Response(const Request &)>;
using callback_t = std::function<void(Connection *)>;

class Connection
{
public:
    Connection(const int &fd, const std::string &clientip, const uint16_t clientport)
        : _fd(fd), _clientip(clientip), _clientport(clientport)
    {
    }

    void Register(callback_t recver, callback_t sender, callback_t excepter)
    {
        _recver = recver;
        _sender = sender;
        _excepter = excepter;
    }

    ~Connection()
    {
    }

public:
    // IO信息
    int _fd;
    std::string _inbuffer;
    std::string _outbuffer;

    // IO处理函数
    callback_t _recver;
    callback_t _sender;
    callback_t _excepter;

    // 用户信息 -- only debug
    std::string _clientip;
    uint16_t _clientport;

    // 也可以给conn带上自己要关心的事件
    uint32_t _events;

    // 回指指针
    EpollServer *_R;

    time_t _lasttime;//该Connection最近一次的访问时间
};

class EpollServer
{
    const static int gnum = 64;

public:
    EpollServer(func_t func, uint16_t port = gport) : _func(func), _port(port)
    {
    }

    void InitServer()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        _epoller.Create();
        AddConnection(_listensock.Fd(), EPOLLIN | EPOLLET);
        logMessage(Debug, "init server success");
    }
    // 事件调度器
    void Dispatcher()
    {
        int timeout = -1;
        while (true)
        {
            LoopOnce(timeout);

            chickLink();
        }
    }

    void LoopOnce(int timeout)
    {
        int n = _epoller.Wait(_revs, gnum, timeout);
        for (int i = 0; i < n; ++i)
        {
            int fd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;
            logMessage(Debug, "正在处理%d上的%s", fd, (events & EPOLLIN) ? "EPOLLIN" : "OTHER");
            // 将所有异常情况转化为recv || send 的异常
            if ((events & EPOLLERR) || (events & EPOLLHUP))
            {
                events |= (EPOLLIN | EPOLLOUT);
            }
            if ((events & EPOLLIN) && ConnIsExists(fd))
            {
                _connections[fd]->_recver(_connections[fd]);
            }
            if ((events & EPOLLOUT) && ConnIsExists(fd))
            {
                _connections[fd]->_sender(_connections[fd]);
            }
        }
    }

    void AddConnection(int fd, uint32_t events, std::string ip = "127.0.0.1", uint16_t port = gport)
    {
        // 设置fd是非阻塞的
        if (events & EPOLLET)
        {
            Util::SetNonBlock(fd);
        }
        // 为fd创建Connection对象
        Connection *conn = new Connection(fd, ip, port);
        if (fd == _listensock.Fd())
        {
            conn->Register(std::bind(&EpollServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
        }
        else
        {
            conn->Register(std::bind(&EpollServer::Recver, this, std::placeholders::_1),
                           std::bind(&EpollServer::Sender, this, std::placeholders::_1),
                           std::bind(&EpollServer::Excepter, this, std::placeholders::_1));
        }
        conn->_events = events;
        conn->_R = this;
        conn->_lasttime = time(nullptr);
        // 将fd,Connection对象添加到_connection
        _connections.insert(std::pair<int, Connection *>(fd, conn));
        // 将fd && events添加到epoll当中
        bool r = _epoller.AddModEvent(fd, events, EPOLL_CTL_ADD);
        assert(r);
        (void)r;

        logMessage(Debug, "AddConnection success, fd: %d, clientinfo: [%s:%d]", fd, ip.c_str(), port);
    }

    bool EnableReadWrite(Connection *conn, bool readable, bool writeable)
    {
        conn->_events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
        return _epoller.AddModEvent(conn->_fd, conn->_events, EPOLL_CTL_MOD);
    }

    // 连接管理器
    void Accepter(Connection *conn)
    {
        do
        {
            int err = 0;
            // 新连接到来
            // logMessage(Debug, "get a new link...");
            std::string clientip;
            uint16_t clientport;
            int sock = _listensock.Accept(&clientip, &clientport, &err);
            if (sock > 0)
            {
                logMessage(Debug, "%s:%d 已经连上了服务器", clientip.c_str(), clientport);
                AddConnection(sock, EPOLLIN | EPOLLET, clientip, clientport);
            }
            else
            {
                if (err == EAGAIN || err == EWOULDBLOCK)
                {
                    break;
                }
                else if (err == EINTR)
                {
                    continue;
                }
                else
                {
                    logMessage(Warning, "errstring: %s, errcode: %d", strerror(err), err);
                }
            }
        } while (conn->_events & EPOLLET);
        logMessage(Debug, "accepter done ...");
    }

    void HandlerRequest(Connection *conn)
    {
        // 根据协议进行数据分析
        bool quit = false;
        while (!quit)
        {
            std::string requestStr;
            // 获取完整报文
            int n = Protocol_ns::ParsePackage(conn->_inbuffer, &requestStr);
            if (n > 0)
            {
                // 提取有效载荷(去报头)
                requestStr = Protocol_ns::RemoveHeader(requestStr, n);
                // 进行反序列化
                Request req;
                req.Deserialize(requestStr);
                // 进行业务处理
                Response resp = _func(req);
                // 序列化
                std::string responseStr;
                resp.Serialize(&responseStr);
                // 添加报头
                responseStr = Protocol_ns::AddHeader(responseStr);

                // 进行返回
                conn->_outbuffer += responseStr;
            }
            else
            {
                quit = true;
            }
        }
    }

    bool RecverHelper(Connection *conn)
    {
        bool ret = true;
        conn->_lasttime = time(nullptr);// 跟新conn最近访问时间
        do
        {
            // 读事件
            char buffer[bsize];
            ssize_t n = recv(conn->_fd, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = '\0';
                conn->_inbuffer += buffer;

                // logMessage(Debug, "inbuffer: %s, [%d]", conn->_inbuffer.c_str(), conn->_fd);
            }
            else
            {
                if (n == 0)
                {
                    conn->_excepter(conn);
                    ret = false;
                    break;
                }
                else
                {
                    if (errno == EAGAIN || errno == EWOULDBLOCK)
                    {
                        break;
                    }
                    else if (errno == EINTR)
                    {
                        continue;
                    }
                    else
                    {
                        conn->_excepter(conn);
                        ret = false;
                        break;
                    }
                }
            }
        } while (conn->_events & EPOLLET);
        return ret;
    }

    void Sender(Connection *conn)
    {
        bool safe = true;
        do
        {
            ssize_t n = send(conn->_fd, conn->_outbuffer.c_str(), conn->_outbuffer.size(), 0);
            if (n > 0)
            {
                conn->_outbuffer.erase(0, n);
                if (conn->_outbuffer.empty())
                {
                    break;
                }
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    safe = false;
                    conn->_excepter(conn);
                    break;
                }
            }
        } while (conn->_events & EPOLLET);
        if (!false)
        {
            return;
        }
        if (!conn->_outbuffer.empty())
        {
            EnableReadWrite(conn, true, true); // 没写完打开对读事件的关心，交给epoll处理
        }
        else
        {
            EnableReadWrite(conn, true, false); // 写完就关闭对读事件的关心
        }
    }

    void Recver(Connection *conn)
    {
        if (!RecverHelper(conn))
        {
            return;
        }
        HandlerRequest(conn);
        // 一般我们在写入的时候，直接写入，没写，才交给epoll
        if (!conn->_outbuffer.empty())
        {
            conn->_sender(conn); // 这里是做第一次的直接写入
        }
    }

    void Excepter(Connection *conn)
    {
        // 先从epoll里面移除fd
        _epoller.DelEvent(conn->_fd);
        // 移除unordered_map中的映射关系
        _connections.erase(conn->_fd);
        // 关闭fd
        close(conn->_fd);
        // 释放conn
        delete conn;

        logMessage(Debug, "Excepter...done, fd: %d, clientinfo: [%s:%d]", conn->_fd, conn->_clientip.c_str(), conn->_clientport);
    }

    bool ConnIsExists(int fd)
    {
        return _connections.find(fd) != _connections.end();
    }

    void chickLink()
    {
        // time_t curr = time(nullptr);
        // for (auto connection : _connections)
        // {
        //     if (connection.second->_lasttime + linkTimeout > curr)
        //     {
        //         continue;
        //     }
        //     else
        //     {
        //         Excepter(connection.second);
        //     }
        // }
    }

    ~EpollServer()
    {
        _listensock.Close();
        _epoller.Close();
    }

private:
    uint16_t _port;
    Sock _listensock;
    Epoller _epoller;
    struct epoll_event _revs[gnum];
    func_t _func;
    std::unordered_map<int, Connection *> _connections;
};